package org.swift.mashup.engine.model;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.swift.commons.client.Call;
import org.swift.commons.client.RestCall;
import org.swift.mashup.wsdl.WebService;
import org.swift.mashup.wsdl.WebServiceFactory;
import org.swift.mashup.wsdl.WsdlLoadException;
import org.swift.mashup.wsdl.WsdlWebService;

@SuppressWarnings("unchecked")
public final class WebServiceRepository {
	private static final Logger logger = Logger.getLogger(WebServiceRepository.class);
	
	private static volatile WebServiceRepository _repository = null;

	private WebServiceFactory factory = new WebServiceFactory() {
		public WebService createWebService(String url) throws WsdlLoadException {			
			return new WsdlWebService(url);			
		}

	};

	private Map<URL, WebService> webServices = new HashMap<URL, WebService>();

	// auto load WSDLs from URLs that you were trying to create calls for that
	// are not
	// loaded.
	private boolean autoLoad = true;

	public static WebServiceRepository getInstance() {
		if (_repository == null) {
			synchronized (WebServiceRepository.class) {
				return (_repository = (_repository == null) ? new WebServiceRepository()
						: _repository);
			}
		}
		return _repository;
	}

	/**
	 * Instantiates a web service provisioner by using the WSDL definition at
	 * the provided URL.
	 * 
	 * @param url
	 * @throws MalformedURLException
	 * @throws WsdlLoadException 
	 */
	public void loadService(URL url) throws MalformedURLException, WsdlLoadException {
		if (logger.isDebugEnabled()){
			logger.debug("Loading WSDL service " + url.toExternalForm());
		}
		webServices.put(url, factory.createWebService(url.toExternalForm()));
	}
	
	private WebService getOrLoadService(URL url) throws MalformedURLException, WsdlLoadException{
		WebService ws = this.webServices.get(url);
		if (ws == null){
			this.loadService(url);
			return this.webServices.get(url);
		}
		return ws;
	}
	
	public WebService getWebService (URL url) throws MalformedURLException, WsdlLoadException{
		return getOrLoadService(url);
	}

	public Call createRestCall(String url, String method) 
		throws MalformedURLException{
		return createRestCall(new URL(url), method);
	}
	
	public Call createRestCall(URL url, String method) {
		return createRestCall(url, method, null, null, null);
	}
	
	public Call createRestCall(String url, String method, String contentType)
		throws MalformedURLException{
		return createRestCall(new URL(url), method, contentType, null, null);
	}
	
	public Call createRestCall(String url, String method, String contentType, String username, String password)
		throws MalformedURLException{
		return createRestCall(new URL(url), method, contentType, username, password);
	}
	
	public Call createRestCall(URL url, String method, String contentType, String username, String password){
		if ("".equals(method) || method == null) {
			method = "GET";
		}
		try {
			String strURL = url != null ? url.toExternalForm() : "";
			return new RestCall(strURL, method, contentType, username, password);
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
	public Call createSoapCall(String url, String operation)
			throws MalformedURLException, WsdlLoadException {
		return createSoapCall(new URL(url), operation);
	}

	public Call createSoapCall(URL url, String operation)
			throws MalformedURLException, WsdlLoadException {
		return createSoapCall(url, operation, isAutoLoad());
	}

	protected Call createSoapCall(URL url, String operation, boolean autoLoad)
			throws MalformedURLException, WsdlLoadException {
		WebService webService = webServices.get(url);
		if (webService == null && operation != null) {
			if (isAutoLoad()) {
				loadService(url);
				// So that it will never recurse, for any reason.
				return createSoapCall(url, operation, false);
			} else {
				throw new RuntimeException(
						"A service definition for the url ["
								+ url
								+ "] was not found in the repository.  If auto-load is set to true, then this WSDL failed to load.");
			}		
		} else {
			return webService.createCall(operation);
		}
	}

	private WebServiceRepository() {

	}

	public boolean isAutoLoad() {
		return autoLoad;
	}

	public void setAutoLoad(boolean autoLoad) {
		this.autoLoad = autoLoad;
	}
}
